/*
 * $Id: dbm.c,v 1.4 2005-12-05 15:11:29 bacon Exp $
 */

#include <xp/dbm/dbm.h>
#include <xp/bas/memory.h>
#include <xp/bas/sysapi.h>

#define XP_DBM_DATA_BLOCK_SIZE 4096
#define XP_DBM_PAGE_BLOCK_SIZE 1024
#define PAIR_MAX        1008
#define SPLIT_MAX       10

#define PAGE_OFFSET(x)  ((x) * XP_DBM_PAGE_BLOCK_SIZE)
#define DATA_OFFSET(x)  ((x) * XP_DBM_DATA_BLOCK_SIZE)

static int __get_page (xp_dbm_t* dbm, xp_size_t hash);
static xp_size_t __hash (const xp_byte_t* str, xp_size_t len);

xp_dbm_t* xp_dbm_open (xp_dbm_t* dbm, const xp_char_t* file)
{
	xp_char_t path[XP_PATH_MAX + 1];

	if (dbm == XP_NULL) {
		dbm = (xp_dbm_t*)xp_malloc (xp_sizeof(xp_dbm_t));
		if (dbm == XP_NULL) return XP_NULL;
		dbm->__dynamic = xp_true;
	}
	else dbm->__dynamic = xp_true;

	xp_strxapp (path, xp_countof(path), file, XP_TEXT(".pag"), XP_NULL);
	if (xp_fio_open(&dbm->page_handle, path,
		XP_FIO_READ | XP_FIO_WRITE | XP_FIO_CREATE, 0600) == XP_NULL) {
		if (dbm->__dynamic) xp_free (dbm);
		return XP_NULL;
	}

	xp_strxapp (path, xp_countof(path), file, XP_TEXT(".dat"), XP_NULL);
	if (xp_fio_open(&dbm->data_handle, path,
		XP_FIO_READ | XP_FIO_WRITE | XP_FIO_CREATE, 0600) == XP_NULL) {
		xp_fio_close (&db->page_handle);
		if (dbm->__dynamic) xp_free (dbm);
		return XP_NULL;
	}
	
	return dbm;
}

void xp_dbm_close (xp_dbm_t* dbm)
{
	xp_fio_close (&db->page_handle);
	xp_fio_close (&db->data_handle);
	if (dbm->__dynamic) xp_free (dbm);
}

int xp_dbm_store (xp_dbm_t* dbm, 
	const xp_dbm_datum_t* key, const xp_dbm_datum_t* value, int flags)
{
	xp_size_t size;

	size = key->size + value->size;

	if (size < 0 || size > PAIRMAX) return -1;
	if (__get_page(dbm, __hash(key->data, key->size)) == -1) return -1;

	if (flags == XP_DBM_REPLACE) 
		__delete_pair (db->page_buffer, key);

	__put_pair (db->page_buffer, key, value);
	return 0;
}

static int __get_dbit (xp_dbm_t* dbm)
{
}

static int __get_page (xp_dbm_t* dbm, xp_size_t hash)
{
	xp_size_t page_no;

	page_no = hash & dbm->hash_mask;
	if (page_no == dbm->page_no) return 0;

	if (xp_fio_seek (&dbm->page_handle, 
		PAGE_OFFSET(page_no), XP_FIO_SEEK_BEGIN) == -1) return -1; 
	if (xp_fio_read (&dbm->page_handle, 
		dbm->page_buffer, xp_sizeof(dbm->page_buffer)) == -1) return -1;

	if (__check_buffer(dbm->page_buffer) == -1) return -1;

	dbm->page_no = page_no;
	return 0;
}


static int __check_page (xp_byte_t* page)
{
	/* TODO */
	return 0;
}

static xp_size_t __hash (const xp_byte_t* str, xp_size_t len)
{
	/* TODO: better hash function */
	xp_size_t n = 0;
	while (len-- > 0) n = *str++ + 65599 * n;
	return n;
}
